home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
umddvi
/
lib
/
pkfont.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-01
|
18KB
|
768 lines
/*
* Copyright (c) 1987 University of Maryland Department of Computer Science.
* All rights reserved. Permission to copy for any purpose is hereby granted
* so long as this copyright notice remains intact.
*/
#ifndef lint
static char rcsid[] = "$Header: pkfont.c,v 2.8 87/08/21 12:44:28 chris Exp $";
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "types.h"
#include "font.h"
#include "num.h"
/*
* PK font operations.
*
* The spelling `nybble' is a concession to the authors of the PK format.
*/
int pk_read(), pk_getgly(), pk_rasterise(), pk_freefont();
struct fontops pkops =
{ "pk", 1.0, pk_read, pk_getgly, pk_rasterise, pk_freefont };
/*
* Local info.
*/
/*
* Commands.
*/
#define PK_XXX1 240 /* 1 byte special */
#define PK_XXX2 241 /* 2 byte special */
#define PK_XXX3 242 /* 3 byte special */
#define PK_XXX4 243 /* 4 byte special */
#define PK_YYY 244 /* METAFONT numspecial */
#define PK_POST 245 /* marks postamble */
#define PK_NO_OP 246 /* do nothing */
#define PK_PRE 247 /* marks preamble */
/* 248..255 undefined */
#define PK_IsUndef(c) ((c) > PK_PRE)
#define PK_ID 89 /* marks this brand of PK file */
/*
* Information about a character packet.
*/
struct cp {
char *cp_packet; /* the beginning of the packet */
int cp_type; /* decoded pre type, see below */
};
#define CP_SHORT 0 /* short preamble */
#define CP_EXT_SHORT 1 /* extended short preamble */
#define CP_LONG 2 /* long preamble */
/*
* The PK details include:
* -> a pointer to the next byte to fetch;
* -> the most recent byte fetched (when we are using nextnyb());
* -> a flag indicating that we have used nybble 0 (bits 4..7) and
* should use nybble 1 next;
* -> the base address of the memory allocated for the PK file;
* -> the value of dyn_f (during character translation);
* -> the repeat count (during rasterisation);
* -> the lowest glyph number that is legal;
* -> the highest glyph number that is legal;
* -> glyph instructions for the standard glyphs;
* -> glyph instructions for more (nonstandard) glyphs;
* and the number of glyphs left unrasterised.
*/
struct pk_details {
char *pk_ptr; /* next byte to fetch */
int pk_c; /* most recent byte fetched, if nybbling */
int pk_1nyb; /* true => nybble 1 is next (bits 0..3) */
char *pk_base; /* base of allocated memory */
int pk_dyn_f; /* the dyn_f value */
int pk_repeat; /* the repeat count */
int pk_minc; /* minimum character value */
int pk_maxc; /* maximum character value */
#define MAXSTD 256 /* maximum `standard' character value */
int pk_gleft; /* number of valid glyphs left uninterpreted */
struct cp pk_cpack[MAXSTD]; /* for characters in [0..MAXSTD) */
struct cp *pk_morec; /* for characters in [MAXSTD..maxc] */
};
/*
* Fetch the next byte from the PK file.
*/
#define nextbyte(pk) pgetbyte((pk)->pk_ptr)
/*
* PK packed number encoding. Nybbles in [1..dyn_f] represent themselves.
* Values in (dyn_f..13] are two-nybble values, and represent values
* dyn_f+1 through (13-dyn_f+1)*16+15. Zero marks a long number; 14 and
* 15 specify repeat counts instead (which are another packed number).
* Note that we cannot represent the number zero as a packed number.
*/
#define PK_LONGNUM 0 /* a `long number' */
#define PK_REPEAT 14 /* set repeat count */
#define PK_REPEAT1 15 /* set repeat to 1 */
/*
* Get the next nybble. This is an expression rendition of
* if (--pk->pk_1nyb < 0) {
* pk->pk_1nyb = 1;
* pk->pk_c = nextbyte(pk);
* return (pk->pk_c >> 4);
* } else
* return (pk->pk_c & 0xf);
*/
#define nextnyb(f) \
(--(pk)->pk_1nyb < 0 ? \
((pk)->pk_1nyb = 1, ((pk)->pk_c = nextbyte(pk)) >> 4) : \
(pk)->pk_c & 0xf)
/*
* Get the pk_details from font f.
*/
#define ftopk(f) ((struct pk_details *) (f)->f_details)
extern int errno;
char *malloc();
/*
* PK subroutines.
*/
/*
* Unpack a packed number.
*/
static int
pk_unpack(pk)
register struct pk_details *pk;
{
register int i, j;
top:
if ((i = nextnyb(pk)) == PK_LONGNUM) {
#if PK_LONGNUM != 0 /* this may be silly, but . . . */
i = 0;
#endif
/*
* Expand a long number. There are one fewer leading
* zeros than there are nonzero digits to obtain, so
* count up the leading zeros, add one, and get that
* many digits. (The `digits' are hexadecimal values.)
*/
do {
i++;
} while ((j = nextnyb(pk)) == 0);
while (--i >= 0) {
j <<= 4;
j += nextnyb(pk);
}
return (j - 15 + (13 - pk->pk_dyn_f) * 16 + pk->pk_dyn_f);
}
if (i <= pk->pk_dyn_f)
return (i);
if (i < PK_REPEAT)
return ((i - pk->pk_dyn_f - 1) * 16 + nextnyb(pk) +
pk->pk_dyn_f + 1);
/*
* There is a repeat count, either one or a packed number.
* Get it first, then start over. (tail recursion)
*/
if (i == PK_REPEAT)
pk->pk_repeat = pk_unpack(pk);
else
pk->pk_repeat = 1;
goto top;
}
/*
* Skip over special commands (PK_XXX?, PK_YYY).
*/
static
skip_specials(f)
struct font *f;
{
struct pk_details *pk = ftopk(f);
register char *p = pk->pk_ptr;
register i32 i;
for (;;) {
switch (UnSign8(*p++)) {
case PK_XXX1:
i = UnSign8(*p++);
p += i;
break;
case PK_XXX2:
pGetWord(p, i);
p += i;
break;
case PK_XXX3:
pGet3Byte(p, i);
p += i;
break;
case PK_XXX4:
pGetLong(p, i);
p += i;
break;
case PK_YYY:
p += 4;
break;
case PK_NO_OP:
break;
case PK_PRE:
error(1, 0, "unexpected PK_PRE in \"%s\"", f->f_path);
break;
default:
p--;
if (PK_IsUndef(UnSign8(*p)))
error(1, 0, "invalid opcode %d in \"%s\"",
f->f_path);
pk->pk_ptr = p;
return;
}
}
}
/*
* Read a PK file.
*/
static int
pk_read(f)
register struct font *f;
{
register struct pk_details *pk;
register char *p;
int i, fd, minc;
struct stat st;
char *reason;
if ((fd = open(f->f_path, 0)) < 0)
return (-1);
pk = NULL; /* prepare for failure */
reason = NULL;
(void) fstat(fd, &st);
if (st.st_size < 4) { /* ??? */
reason = "file is too small";
goto fail;
}
if ((pk = (struct pk_details *) malloc(sizeof (*pk))) == NULL)
goto fail;
pk->pk_morec = NULL;
if ((pk->pk_base = malloc(st.st_size)) == NULL)
goto fail;
if (read(fd, pk->pk_base, st.st_size) != st.st_size)
goto fail;
pk->pk_ptr = pk->pk_base;
if (nextbyte(pk) != PK_PRE) {
reason = "file does not begin with PK_PRE";
goto fail;
}
if (nextbyte(pk) != PK_ID) {
reason = "bad PK_ID";
goto fail;
}
i = nextbyte(pk);
p = pk->pk_ptr + i + 4; /* skip comment and design size */
pGetLong(p, f->f_checksum);
pk->pk_ptr = p + 4 + 4; /* skip hppp, vppp */
f->f_details = (char *) pk;
/* scan the characters, fail if necessary */
if (scan_characters(f, &reason))
goto fail;
/* ignore the postamble */
/* COMPRESS pk->pk_base DATA? */
if (FontHasGlyphs(f, pk->pk_minc, pk->pk_maxc + 1))
goto fail;
(void) close(fd);
return (0);
fail:
if (reason) {
error(0, 0, "%s", reason);
error(0, 0, "(are you sure %s is a PK file?)", f->f_path);
errno = 0;
}
if (pk != NULL) {
if (pk->pk_base != NULL)
free(pk->pk_base);
if (pk->pk_morec != NULL)
free((char *) pk->pk_morec);
free((char *) pk);
}
(void) close(fd);
return (-1);
}
/*
* Scan through the characters in the PK file, and set the offsets
* and preamble types for each of the character packets.
*/
static int
scan_characters(f, reason)
struct font *f;
char **reason;
{
register struct pk_details *pk = ftopk(f);
register i32 c, pl;
register char *p;
register struct cp *cp;
int type;
#ifdef lint
/* reason will be used someday ... I think */
reason = reason;
#endif
/* set up the minimisers and the glyph count */
pk->pk_minc = 1;
pk->pk_maxc = 0;
pk->pk_gleft = 0;
/* mark all character packets as untouched */
for (cp = pk->pk_cpack, c = MAXSTD; --c >= 0; cp++)
cp->cp_packet = NULL;
/*
* Loop through the packets until we reach a POST, skipping
* the glyph instructions themselves after each definition,
* and specials (if any) before each.
*/
for (;; pk->pk_ptr = p + pl) {
skip_specials(f);
p = pk->pk_ptr;
if ((c = pgetbyte(p)) == PK_POST)
break; /* whoops, done after all */
/*
* Look at the low three bits to decide preamble size.
* A value of 7 is a `long preamble'; 4, 5, and 6 are
* `extended short preambles'; and 0, 1, 2, and 3 are
* `short preambles'.
*
* We ignore most of the preamble, reading only the
* `packet length' and the character code at this time.
*/
switch (c & 7) {
case 7: /* long */
type = CP_LONG;
pGetLong(p, pl);
pGetLong(p, c);
break;
case 6:
case 5:
case 4: /* extended short */
type = CP_EXT_SHORT;
pGetWord(p, pl);
pl += (c & 3) << 16;
c = pgetbyte(p);
break;
default: /* short */
type = CP_SHORT;
pl = ((c & 3) << 8) + pgetbyte(p);
c = pgetbyte(p);
break;
}
if (c >= MAXSTD) {
/*
* BEGIN XXX - should alloc pk_morec, but is hard
* and not now useful
*/
error(0, 0, "ignoring character %d in \"%s\"",
f->f_path);
error(0, 0, "because some darn programmer was lazy!");
continue;
/* END XXX */
} else
cp = &pk->pk_cpack[c];
cp->cp_packet = pk->pk_ptr;
cp->cp_type = type;
/* adjust range */
if (c < pk->pk_minc)
pk->pk_minc = c;
if (c > pk->pk_maxc)
pk->pk_maxc = c;
pk->pk_gleft++; /* and count the glyph */
}
return (0); /* no problems */
}
/*
* Obtain the specified range of glyphs.
*/
static int
pk_getgly(f, l, h)
register struct font *f;
int l, h;
{
register struct pk_details *pk = ftopk(f);
register char *p;
register struct glyph *g;
register int i;
register struct cp *cp;
if (pk == NULL)
panic("pk_getgly(%s)", f->f_path);
for (i = l; i < h; i++) {
if (i < MAXSTD)
cp = &pk->pk_cpack[i];
else {
if (i > pk->pk_maxc)
panic("pk_getgly(%s, %d)", f->f_path, i);
cp = &pk->pk_morec[i - MAXSTD];
}
p = cp->cp_packet;
if (p == NULL) /* glyph is not valid */
continue;
g = f->f_gly[i];
p++; /* skip flag */
switch (cp->cp_type) {
case CP_LONG:
p += 8; /* skip packet len, character code */
pGetLong(p, g->g_tfmwidth);
#ifdef notyet
pGetLong(p, g->g_xescapement);
pGetLong(p, g->g_yescapement);
#else
p += 8;
#endif
pGetLong(p, g->g_width);
pGetLong(p, g->g_height);
pGetLong(p, g->g_xorigin);
pGetLong(p, g->g_yorigin);
break;
case CP_EXT_SHORT:
p += 3; /* skip packet len, character code */
pGet3Byte(p, g->g_tfmwidth);
#ifdef notyet
{ i32 dm; pGetWord(p, dm);
g->g_xescapement = dm << 16; }
g->g_yescapement = 0;
#else
p += 2; /* skip dm */
#endif
pGetWord(p, g->g_width);
pGetWord(p, g->g_height);
pGetWord(p, g->g_xorigin);
g->g_xorigin = Sign16(g->g_xorigin);
pGetWord(p, g->g_yorigin);
g->g_yorigin = Sign16(g->g_yorigin);
break;
case CP_SHORT:
p += 2; /* skip packet len, character code */
pGet3Byte(p, g->g_tfmwidth);
#ifdef notyet
g->g_xescapement = pgetbyte(p) << 16;
g->g_yescapement = 0;
#else
p++; /* skip dm */
#endif
g->g_width = pgetbyte(p);
g->g_height = pgetbyte(p);
g->g_xorigin = pgetbyte(p);
g->g_xorigin = Sign8(g->g_xorigin);
g->g_yorigin = pgetbyte(p);
g->g_yorigin = Sign8(g->g_yorigin);
break;
}
g->g_flags = GF_VALID;
g->g_un.g_details = p;
}
return (0);
}
/*
* Bit masks for pk_rasterise().
*/
static char bmask[8] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
static char rbits[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
/*
* Obtain rasters for the specified glyphs.
*/
static int
pk_rasterise(f, l, h)
struct font *f;
int l, h;
{
struct pk_details *pk0;
struct glyph *g0;
char *p0, *rp0;
int flag, ii;
if ((pk0 = ftopk(f)) == NULL)
panic("pk_rasterise(%s)", f->f_path);
for (ii = l; ii < h; ii++) {
{
register struct glyph *g;
register char *p;
register int i;
g = f->f_gly[i = ii];
if ((g->g_flags & GF_VALID) == 0)
continue; /* no glyph */
if (!HASRASTER(g)) /* empty raster */
goto done;
/*
* Allocate a raster.
*/
rp0 = malloc(((g->g_width + 7) >> 3) * g->g_height);
if ((g->g_raster = rp0) == NULL)
return (-1);/* ??? */
g->g_rotation = ROT_NORM;
/*
* Pick up the flag byte, then start at the real
* packet, which we saved in g_details.
*/
if (i < MAXSTD)
p = pk0->pk_cpack[i].cp_packet;
else
p = pk0->pk_morec[i - MAXSTD].cp_packet;
flag = UnSign8(*p);
p0 = g->g_un.g_details;
g0 = g;
}
if ((pk0->pk_dyn_f = flag >> 4) == 14) {
register char *p = p0, *rp = rp0;
register int j, ls, rs, i, w;
/*
* Expand a bit-packed representation.
* If we get lucky, it is byte packed and
* we can just copy it over.
*/
i = g0->g_height;
j = g0->g_width;
if ((j & 7) == 0) {
bcopy(p, rp, i * (j >> 3));
goto done;
}
/*
* No such luck.
*/
w = j;
ls = 0;
while (--i >= 0) {
#if defined(vax) && !defined(lint)
/* have to work on the compiler someday */
rs = ls - 8;
#else
rs = 8 - ls;
#endif
/* know j always != 8 */
for (j = w; j > 8; j -= 8) {
#if defined(vax) && !defined(lint)
asm(" movb (r11)+,r0");
asm(" ashl r8,r0,r0");
asm(" movb r0,(r10)");
asm(" movzbl (r11),r0");
asm(" ashl r7,r0,r0");
asm(" bisb2 r0,(r10)+");
#else
*rp = *p++ << ls;
*rp++ |= UnSign8(*p) >> rs;
#endif
}
/*
* We need j more bits; there are rs
* bits available at *p. Ask for j,
* which gets min(j, rs).
*/
#if defined(vax) && !defined(lint)
/*void*/; /* avoid asm() label botch */
asm(" movb (r11),r0");
asm(" ashl r8,r0,r0");
asm(" mcomb _bmask[r9],r1");
asm(" bicb2 r1,r0");
asm(" movb r0,(r10)+");
#else
*rp++ = (*p << ls) & bmask[j];
#endif
/* account for j bits */
ls += j; ls &= 7;
/* then adjust j based on rs */
#if defined(vax) && !defined(lint)
j += rs;
#else
j -= rs;
#endif
/* still need j more bits */
if (j < 0) /* got them all */
continue;
p++;
if (j == 0) /* there were just enough */
continue;
/* take j more bits */
#if defined(vax) && !defined(lint)
/*void*/; /* avoid asm() label botch */
asm(" mcomb _bmask[r9],r0");
asm(" bicb3 r0,(r11),r0");
asm(" movzbl r0,r0");
asm(" ashl r7,r0,r0");
asm(" bisb2 r0,-1(r10)");
#else
rp[-1] |= UnSign8(*p & bmask[j]) >> rs;
#endif
}
} else {
register struct pk_details *pk = pk0;
register int on = flag & 8 ? 0xff : 0;
register char *rowp; /* pointer into this row */
register int j; /* trimmed run count */
register int k; /* misc */
register int b; /* bit index in current col */
register int i; /* run count */
register int colsleft; /* columns left this row */
register int rowsleft; /* rows left */
static char *row; /* a one-row buffer */
static int rowsize; /* and its size in bytes */
int wb; /* row width in bytes */
wb = (g0->g_width + 7) >> 3;
if (rowsize < wb) { /* get more row space */
if (row)
free(row);
/* keep a slop byte */
row = malloc((unsigned) (wb + 1));
if (row == NULL)
return (-1); /* ??? */
rowsize = wb;
}
bzero(row, wb);
rowsleft = g0->g_height;
colsleft = g0->g_width;
pk->pk_repeat = 0;
pk->pk_ptr = p0;
pk->pk_1nyb = 0; /* start on nybble 0 */
rowp = row;
b = 0;
while (rowsleft > 0) { /* do all rows */
/* EXPAND IN LINE? */
i = pk_unpack(pk);
/*
* Work until the run count is exhausted
* (or at least pretty tired).
*
* (Okay, so the joke is stolen!)
*/
while ((j = i) > 0) {
/*
* If the count is more than the
* rest of this row, trim it down.
*/
if (j > colsleft)
j = colsleft;
i -= j; /* call them done */
/*
* We need k=8-b bits to finish
* up the current byte. If we
* can finish it, do so; the proper
* bits to set are in rbits[k].
*/
if (j >= (k = 8 - b)) {
j -= k;
colsleft -= k;
*rowp++ |= on & rbits[k];
b = 0;
}
/*
* Set any full bytes.
*/
while (j >= 8) {
*rowp++ = on;
j -= 8;
colsleft -= 8;
}
/*
* Finally, begin a new byte, or
* add to the current byte, with
* j more bits. We know j <= 8-b.
* (If j==0, we may be writing on
* our slop byte, which is why we
* keep one around....)
*/
if (j > 8-b) panic("pk_rasterise j>8-b");
*rowp |= (on & bmask[j]) >> b;
colsleft -= j;
b += j; b &= 7;
if (colsleft == 0) {
pk->pk_repeat++;
rowsleft -= pk->pk_repeat;
while (--pk->pk_repeat >= 0) {
bcopy(row, rp0, wb);
rp0 += wb;
}
if (rowsleft == 0 && i) panic("pk_rasterise leftover bits");
pk->pk_repeat = 0;
rowp = row;
colsleft = g0->g_width;
bzero(row, wb);
b = 0;
}
}
on = 0xff - on;
}
}
done:
/*
* Successfully converted another glyph.
*/
pk0->pk_gleft--;
}
if (pk0->pk_gleft < 0)
panic("%s: gleft==%d", f->f_path, pk0->pk_gleft);
if (pk0->pk_gleft == 0) {
free(pk0->pk_base);
if (pk0->pk_morec != NULL)
free((char *) pk0->pk_morec);
free((char *) pk0);
f->f_details = NULL;
}
return (0);
}
/*
* Discard the font details.
*/
static
pk_freefont(f)
struct font *f;
{
register struct pk_details *pk = ftopk(f);
if (pk != NULL) {
free(pk->pk_base);
if (pk->pk_morec != NULL)
free((char *) pk->pk_morec);
free((char *) pk);
}
}